#include<iostream>
#include<pthread.h>
#include<semaphore.h>
#include<queue>

namespace Blockqueue
{
    template<class T>
    class blockqueue
    {
    public:
        blockqueue(const int&& cap)
        :_cap(cap)
        {
            sem_blank = _cap;
            pthread_mutex_init(&_mutex,NULL);
            sem_init(&p_sem,0,sem_blank);//p_sem
            sem_init(&c_sem,0,sem_data);
        }

        void product(T& in)
        {
            sem_wait(&p_sem);
            pthread_mutex_lock(&_mutex);
            _queue.push(in);   
            sem_post(&c_sem);
            pthread_mutex_unlock(&_mutex);
        }

        void consume(T* out)
        {
            sem_wait(&c_sem);
            pthread_mutex_lock(&_mutex);
            *out = _queue.front();
            _queue.pop();
            sem_post(&p_sem);
            pthread_mutex_unlock(&_mutex);

        }

        ~blockqueue()
        {
            pthread_mutex_destroy(&_mutex);
            sem_destroy(&p_sem);
            sem_destroy(&c_sem);
        }


    private:
        std::queue<T> _queue;
        int _cap;
        pthread_mutex_t _mutex;

        sem_t p_sem;
        int sem_blank;

        sem_t c_sem;
        int sem_data = 0;
    };
    

    
    
}